/*
	This file is part of Vajolet.

    Vajolet is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Vajolet is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Vajolet.  If not, see <http://www.gnu.org/licenses/>
*/

#ifndef _TRANSPOSITION
#define _TRANSPOSITION

#include "vajolet.h"
#include "move.h"
#include <stdlib.h>
#include <iostream>


class transEntry
{
public:
	//U64 hash;			// hash value
	unsigned int hash;

    score value;		// value (score)
	score staticValue;	// static Value
	unsigned short int move;			// best move
    char type;			// (see bttNnnn)
	char searchId;		//
    unsigned char depth;
	unsigned short int threatMove;

    // convert from relative to absolute value (if_mate)
    inline score getValue( int ply ) const
    {
        if ( abs(value) >= MATE_IN_MAX_PLY )
        {
            return value < 0 ? value + ply : value - ply;
        }
        return value;
    }
};

struct transCluster {
  transEntry data[4];
};

class transTable{
	
	transCluster* table;
	
	unsigned long long numSearch,searchHit;
	
	unsigned long long insertedItems;
public:
	unsigned long long usedEntries;
	unsigned int entries;
	int MBsize;
	unsigned char searchId;
	enum eResult{
		HASH_NOT_FOUND=-32768
	};
	enum eTTtype{
		TTempty,
		TTexact,
		TTalpha,
		TTbeta
	};

	transTable(int MB=1){
		table=NULL;
		setSize(MB);


		numSearch=0;
		searchHit=0;
		searchId=0;


	}

	void setSize(int MB){
		MBsize=MB;
		unsigned int e=1;
		if(table!=NULL){
			free(table);
		}

		
		//std::cout<<sizeof(transCluster)<<std::endl;
		entries=(unsigned int )((float)MB*1024.0*1024.0/sizeof(transCluster));
		//std::cout<<entries<<std::endl;
		for(int i=0;i<100;i++){
			if(e<entries){
				e<<=1;
			}
			
		}
		if(e>entries){
			e>>=1;
		}

		entries=e;
		//std::cout<<entries<<std::endl;
		table=(transCluster*)calloc(entries,sizeof(transCluster));
		numSearch=0;
		searchHit=0;
		searchId=0;


	}

	inline void increaseSearchId(){
		searchId++;
		usedEntries=0;
		
	}

	inline void updateSearchId(transEntry *t){
		t->searchId=searchId;

	}

	inline transCluster* firstEntry(U64 & hash){
		//return entries>0 ? (transCluster *)(&table[hash%(entries)]) : (transCluster *)NULL;
		//return (&table[hash%(entries)]);
		return table+(((unsigned int )hash)&(entries-1));
	}


	void save(U64 hash,int depth, int val, eTTtype type, Move best,int ply,score staticValue,Move threatMove);
	transEntry* probe(U64 hash, Move & bestMove);

	void printStats();
	void clearStats(){
		numSearch=0;
		searchHit=0;
		insertedItems=0;

	};
};

#endif
